#!/usr/bin/env node
//声明脚本执行环境为 node
//@todo 卡在 npm link 了
const {resolve, dirname, join} = require("path");
const fs = require("fs");

const defConf = {
    entry: "./src/index.js",   //不应该是 package.json 的 main 字段的 js 吗
    filename: "bundle.js"
};
//默认是这个名字，但是真实名字应该是可以从 shell 传入
const config = {...defConf, ...(require(resolve("./kkb.config.js")))};

class KkbPack{
    constructor(config){
        this.config = config;
        this.entry = config.entry;
        this.root = process.cwd();  //当亲工作目录
        //存储所有代码片段的 hash
        this.modules = {};
        this.output = config.output;
    }
    /**
     * 根据入口，创建导出 bundle.js
     * @param {*} modulePath 
     * @param {*} name 
     */
    createMoudle(modulePath, name){
        //循环引用的问题解决
        if(this.modules[modulePath]){
            //报错 或者 忽略这个引用，自己看着办
        }
        //同步读取文件内容，也就是阻塞读取
        var fileContent = fs.readFileSync(modulePath,"utf-8");
        console.log("name:");
        console.log(name);
        //获取文件父路径
        const {code, deps} = this.parse(fileContent, dirname(name));
        console.log("code:");
        console.log(code);
        console.log("deps");
        console.log(deps);
        this.modules[name] = `function(module,exports,__kkb_require__){ eval('${code}') }`;
        //循环获取所有依赖数组的内容(因为是从入口层层向下，所以一定是还没有解析的)
        deps.forEach(dep=>{
            this.createMoudle(resolve(this.root,dep),("./"+dep));
        });
        //接下来替换 require 为 _webpack_require__、弄清楚模块依赖关系，返回构建后的文件
    }
    parse(code, parent){
        let deps = [];
        let r = /require\((.*)\)/g;
        //路径修正，单分号的统一为双分号
        code = code.replace(r, function(match, arg){
            //去掉路径中的字符串，需要parent是因为这是相对路径，但是为啥相对路径需要去掉分号呢？
            let retPath = join(parent, arg.replace(/'|"/g,''));
            deps.push(retPath);
            return `__kkb_require__("${retPath}")`;
        });
        return {code,deps};
    }
    start(){
        console.log(this.config);
        console.log('开始解析文件的依赖');
        //拼接起当前入口和工作目录，得到绝对路径
        var entryPath = resolve(this.root, this.entry);
        //从入口开始，查找 require、import，得到依赖关系，require、import 替换为 __kkb_require__
        this.createMoudle(entryPath, this.entry);
        this.generateFile();
        console.log(this.modules);
    }
    /**
     * 入口文件生成
     */
    generateFile(){
        let template = fs.readFileSync(resolve(__dirname,"./template.js"),"utf-8");
        //这样替换字符串引号不会出问题吗？
        this.template = template.replace("__entry__", this.entry).replace("__modules_content__", this.generateModulesStr()).replace(/\n\t/g,"");
        fs.writeFileSync(resolve(this.output.path,this.output.filename), this.template);
        console.log("写入文件完毕");
    }
    /**
     * 生成 this.models 对应的字符串
     */
    generateModulesStr(){
        let arr = [];
        Object.keys(this.modules).forEach(name=>{
            arr.push(`"${name}":${this.modules[name]}`);
        });
        return `\{${arr.join(",")}\}`;
    }
    handlePlugins(){
        let plugins = this.config.plugins;
        plugins.forEach(plugin=>{
            plugins.apply(this);
        })
    }
}

const kkb = new KkbPack(config);
kkb.start();